Java Database Programming with JDBC Java Database Programming with JDBC
by Pratik Patel
Coriolis, The Coriolis Group
ISBN: 1576100561   Pub Date: 10/01/96
  

Previous Table of Contents Next


Let’s take a closer look at what’s going on here. The first thing we do is create a Statement object to “fake out” the ResultSet object that we will be creating to return back to the application. The ResultSet object is dependent upon a Statement object, so we’ll give it one. The next thing we do is create all of the column information. Note that all of the required columns are given in the JDBC API specification. The add method simply adds a SimpleTextColumn object to the Hashtable of columns:

protected  void  add(
    Hashtable h,
     int col,
    String name,
    int type)
{
     h.put(new Integer(col), new SimpleTextColumn(name,type));
}

Next, we create another Hashtable to hold all of the data for all of the catalog rows. The Hashtable contains an entry for each row of data. The entry contains the key, which is the row number, and the data value, which is yet another Hashtable whose key is the column number and whose data value is a CommonValue object containing the actual data. Remember that the CommonValue class provides us with the mechanism to store data and coerce it as requested by the application. If a column is null, we simply cannot store any information in the Hashtable for that column number.

After some sanity checking to ensure that we really need to look for the catalog information, we get a list of all of the tables. The getTables method in the Connection class provides us with a list of all of the SimpleText data files:

public  Hashtable  getTables(
      String dir,
     String table)
{
     Hashtable list = new Hashtable();

     // Create a FilenameFilter object. This object will only allow
    // files with the .SDF extension to be seen.
     FilenameFilter  filter = new SimpleTextEndsWith(
                    SimpleTextDefine.DATA_FILE_EXT);
 
     File file = new File(dir);

      if (file.isDirectory()) {

        // List all of the files in the directory with the .SDF extension
           String entries[] = file.list(filter);
       SimpleTextTable tableEntry;

         // Create a SimpleTextTable entry for each, and put in
        // the Hashtable.
          for (int i = 0; i < entries.length; i++) {

             // A complete driver needs to further filter the table
          // name here.
              tableEntry = new SimpleTextTable(dir, entries[i]);
                   list.put(new Integer(i), tableEntry);

        }
    }

     return list;
}

Again, I use a Hashtable for each table (or file in our case) that is found. By now, you will have realized that I really like using Hashtables; they can grow in size dynamically and provide quick access to data. And because a Hashtable stores data as an abstract Object, I can store whatever is necessary. In this case, each Hashtable entry for a table contains a SimpleTextTable object:

public   class   SimpleTextTable
     extends        Object
{
//------------------------------------------------------------------------
     // Constructor
//------------------------------------------------------------------------
      public SimpleTextTable(
           String dir,
           String file)
    {
           this.dir = dir;
           this.file = file;

         // If the filename has the .SDF extension, get rid of it
          if (file.endsWith(SimpleTextDefine.DATA_FILE_EXT)) {
            name = file.substring(0, file.length() -
                      SimpleTextDefine.DATA_FILE_EXT.length());
        }
        else {
            name = file;
        }
    }

     public String dir;
     public String file;
    public String name;
}

Notice that the constructor strips the file extension from the given file name, creating the table name.

Now, back to the getTables method for DatabaseMetaData. Once a list of all of the tables has been retrieved, the Hashtable used for storing all of the rows is generated. If you were to add additional filtering, this is the place that it should be done. Finally, a new ResultSet object is created and initialized. One of the constructors for the ResultSet class accepts two Hashtables: one for the column information (SimpleTextColumn objects), and the other for row data (CommonValue objects). We’ll see later how these are handled by the ResultSet class. For now, just note that it can handle both in-memory results (in the form of a Hashtable) and results read directly from the data file.

Statement

The Statement class contains methods to execute SQL statements directly against the database and to obtain the results. A Statement object is created using the createStatement method from the Connection object. Of note in Listing 10.21 are the three methods used to execute SQL statements: executeUpdate, executeQuery, and execute. In actuality, you only need to worry about implementing the execute method; the other methods use it to perform their work. In fact, the code provided in the SimpleText driver should be identical for all JDBC drivers.

Listing 10.21 Executing SQL statements.

//------------------------------------------------------------------------
// executeQuery - JDBC API
// Execute an SQL statement that returns a single ResultSet.
//
//    sql    Typically this is a static SQL SELECT statement.
//
// Returns the table of data produced by the SQL statement.
//------------------------------------------------------------------------
public  ResultSet  executeQuery(
      String sql)
     throws SQLException
{
      if (traceOn()) {
           trace("@executeQuery(" + sql + ")");
    }

      java.sql.ResultSet rs = null;

    // Execute the query. If execute returns true, then a result set
    // exists.
     if (execute(sql)) {
          rs = getResultSet();
    }
    else {          // If the statement does not create a ResultSet, the
                    // specification indicates that an SQLException should
                    // be raised.
        throw new SQLException("Statement did not create a ResultSet");
    }
     return rs;
}

//------------------------------------------------------------------------
// executeUpdate - JDBC API
// Execute an SQL INSERT, UPDATE, or DELETE statement. In addition,
// SQL statements that return nothing, such as SQL DDL statements,
// can be executed.
//
//    sql    an SQL INSERT, UPDATE, or DELETE statement, or an SQL
//        statement that returns nothing.
//
// Returns either the row count for INSERT, UPDATE, or DELETE; or 0
// for SQL statements that return nothing.
//------------------------------------------------------------------------
public   int   executeUpdate(
      String sql)
     throws SQLException
{
      if (traceOn()) {
           trace("@executeUpdate(" + sql + ")");
    }
     int count = -1;

    // Execute the query. If execute returns false, then an update
    // count exists.
     if (execute(sql) == false) {
         count = getUpdateCount();
    }
    else {
        // If the statement does not create an update count, the
         // specification indicates that an SQLException should be raised.
        throw new SQLException("Statement did not create an update
          count");
    }

    return count;
}


Previous Table of Contents Next